package liming.tool.data;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 数据装载基本类，基于Map集合实现数据存储功能。
 * 支持克隆、序列化操作，并提供版本控制和类型安全的数据存取方法。
 *
 * @implNote 通过泛型方法实现类型安全的存取，内部使用HashMap作为存储结构
 */
public class DataObject implements Cloneable, Serializable {
    //===================== 版本控制常量 ========================//
    /** 版本号数组，格式：[主版本, 副版本, 序列号] */
    private static final int[] VERSION = new int[]{1,0, Integer.parseInt(LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")))};
    /** 自动生成ID的标准长度 */
    private static final Integer ID_LENGTH = 64;
    /** 主版本号 - 重大变更时递增，不向下兼容 */
    private static final int MajorVersionNumber = VERSION[0];
    /** 副版本号 - 功能优化时递增，保持兼容 */
    private static final int MinorVersionNumber = VERSION[1];
    /** 序列号 - 每次构建时递增的序列标识 */
    private static final int SerialNumber = VERSION[2];


    private static final long serialVersionUID = MajorVersionNumber;

    //===================== 实例字段 ========================//
    /** 核心数据存储结构 */
    private final Map<String, Object> map;
    /** 实例版本信息 */
    private int majorVersionNumber, minorVersionNumber, serialNumber;

    //=========================== 构造方法 =====================================

    /**
     * 构建空数据容器，初始化默认版本信息
     */
    public DataObject() {
        map = new HashMap<>();
        setVersion(MajorVersionNumber, MinorVersionNumber, SerialNumber);
    }

    /**
     * 通过现有Map构造数据容器（浅拷贝）
     * @param data 要导入的原始数据集合
     */
    public DataObject(Map<?,?> data) {
        this();
        putAll(data);
    }

    /**
     * 拷贝构造方法（浅拷贝）
     * @param dataObject 要复制的数据容器
     */
    public DataObject(DataObject dataObject) {
        this();
        putAll(dataObject.getMap());
        setVersion(dataObject.majorVersionNumber, dataObject.minorVersionNumber, dataObject.serialNumber);
    }

    //===================== 版本控制 ========================//

    /**
     * 获取核心版本描述字符串
     * @return 格式化的版本信息，如"版本号=1.0.250118"
     */
    public static String VERSION() {
        return "版本号=" + MajorVersionNumber + "." + MinorVersionNumber + "." + SerialNumber;
    }

    /**
     * 获取当前实例的版本号数组
     * @return int数组[主版本, 副版本, 序列号]
     */
    public int[] getVersion() {
        return new int[]{MajorVersionNumber,MinorVersionNumber,SerialNumber};
    }

    /**
     * 设置实例版本信息（供子类继承使用）
     * @param majorVersionNumber 主版本号
     * @param minorVersionNumber 副版本号
     * @param serialNumber 序列号
     */
    protected void setVersion(int majorVersionNumber, int minorVersionNumber, int serialNumber) {
        this.majorVersionNumber = majorVersionNumber;
        this.minorVersionNumber = minorVersionNumber;
        this.serialNumber = serialNumber;
    }

    //===================== 数据写入操作 ========================//

    /**
     * 添加键值对（强制覆盖）
     * @param key 键（自动进行字符串驻留优化）
     * @param value 值对象
     * @return 当前实例（支持链式调用）
     */
    public synchronized DataObject put(String key, Object value) {
        return put(key, value, true);
    }

    /**
     * 条件添加键值对
     * @param key 键（自动进行字符串驻留优化）
     * @param value 值对象
     * @param override 当键存在时是否覆盖
     * @return 当前实例（支持链式调用）
     */
    public synchronized DataObject put(String key, Object value, boolean override) {
        key = key.intern();
        if (override || !map.containsKey(key))
            map.put(key, value);
        return this;
    }

    /**
     * 批量添加Map数据（强制覆盖）
     * @param values 要添加的键值对集合
     * @return 当前实例（支持链式调用）
     */
    public synchronized DataObject putAll(Map<?, ?> values) {
        for (Object key : values.keySet())
            put(key.toString().intern(), values.get(key));
        return this;
    }

    /**
     * 合并另一个ReceiveMap实例数据（强制覆盖）
     * @param dataObject 数据源实例
     * @return 当前实例（支持链式调用）
     */
    public synchronized DataObject putAll(DataObject dataObject) {
        map.putAll(dataObject.map);
        return this;
    }

    //===================== 数据读取操作 ========================//

    /**
     * 移除指定键并返回被删除的键值对
     * @param key 主键
     * @param keys 其他键（可变参数）
     * @return 包含被删除键值对的Map（不会返回null）
     */
    public synchronized Map<String, Object> remove(String key, String... keys) {
        key = key.intern();
        Map<String, Object> map = new HashMap<>();
        map.put(key, this.map.remove(key));
        for (String k : keys) {
            k = k.intern();
            map.put(k, this.map.remove(k));
        }
        return map;
    }

    /**
     * 强制获取值（自动类型转换）
     * @param key 查询键
     * @return 值对象（自动类型转换）
     * @throws RuntimeException 当键不存在时抛出
     * @param <T> 返回值类型
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key) {
        key = key.intern();
        return (T)get(key, Object.class);
    }

    /**
     * 类型安全的值获取
     * @param key 查询键
     * @param clazz 目标类型Class对象
     * @return 类型转换后的值对象
     * @throws RuntimeException 当键不存在或类型不匹配时抛出
     * @param <T> 返回值类型
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key, Class<T> clazz) {
        key = key.intern();
        if (!map.containsKey(key))
            throw new RuntimeException("key= " + key + " 在Receive中不存在");
        Object object = map.get(key);
        if (object == null)
            return null;
        if (clazz.isInstance(object))
            return (T) object;
        throw new RuntimeException("key= " + key + " ,无法将" + object.getClass().getName() + " 转化为 " + clazz.getName() + " 的实例 ");
    }

    //===================== 安全读取操作 ========================//

    /**
     * 安全获取值（允许默认null）
     * @param key 查询键
     * @return 值对象或null
     * @param <T> 返回值类型
     */
    @SuppressWarnings("unchecked")
    public<T> T opt(String key) {
        key = key.intern();
        return (T)opt(key, Object.class, null);
    }

    /**
     * 类型安全的安全获取
     * @param key 查询键
     * @param clazz 目标类型Class对象
     * @return 类型转换后的值或null
     * @param <T> 返回值类型
     */
    public <T> T opt(String key, Class<T> clazz) {
        key = key.intern();
        return opt(key, clazz, null);
    }

    /**
     * 带默认值的类型安全获取
     * @param key 查询键
     * @param clazz 目标类型Class对象
     * @param defaultObject 默认值（当键不存在或类型不匹配时返回）
     * @return 值对象或默认值
     * @param <T> 返回值类型
     */
    public <T> T opt(String key, Class<T> clazz, T defaultObject) {
        key = key.intern();
        return opt(key, clazz, defaultObject, false);
    }

    /**
     * 全功能安全获取方法
     * @param key 查询键
     * @param clazz 目标类型Class对象
     * @param defaultObject 默认值
     * @param keep 当键不存在时，是否将默认值写入存储
     * @return 值对象或默认值
     * @param <T> 返回值类型
     */
    public <T> T opt(String key, Class<T> clazz, T defaultObject, boolean keep) {
        key = key.intern();
        Object object = map.getOrDefault(key, defaultObject);
        if (keep) {
            map.put(key, object);
        } else {
            if (object == null)
                return null;
            if (clazz.isInstance(object))
                return (T) object;
        }
        return defaultObject;
    }

    /**
     * 字符串类型安全获取
     * @param key 查询键
     * @param value 默认字符串值
     * @return 字符串形式的值或默认值
     */
    public String optString(String key, String value) {
        key = key.intern();
        Object object = opt(key);
        return object == null ? value : object.toString();
    }

    //===================== 容器状态操作 ========================//

    public Set<String> keySet() {
        return map.keySet();
    }

    /**
     * 获取底层存储Map的副本（浅拷贝）
     * @return 当前数据的Map形式副本
     */
    public Map<String, Object> getMap() {
        return map;
    }

    /**
     * 检查键是否存在
     * @param key 查询键
     * @return 存在返回true
     */
    public boolean containsKey(String key) {
        return map.containsKey(key.intern());
    }

    /**
     * 类型安全的键存在性检查
     * @param key 查询键
     * @param tClass 期望的类型Class
     * @return 当且仅当键存在且值类型匹配时返回true
     * @param <T> 期望类型
     */
    public <T> boolean containsKey(String key,Class<T> tClass) {
        key = key.intern();
        return map.containsKey(key)&&tClass.isInstance(map.get(key));
    }

    //===================== 对象基本方法 ========================//

    /**
     * 创建当前实例的浅拷贝副本
     * @throws CloneNotSupportedException 理论上不会抛出
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        super.clone();
        return new DataObject(this);
    }
    public static DataObject valueOfMap(Object object){
        Object value = valueOfMap0(object);
        if(value instanceof DataObject)
            return (DataObject)value;
        if(value instanceof Map)
            return new DataObject((Map)value);
        return new DataObject().put("default", value);
    }

    private static Object valueOfMap0(Object object) {
        if(object instanceof DataObject){
            DataObject dataObject = new DataObject();
            ((DataObject)object).map.forEach((k,v)->{
               if(v instanceof DataObject||v instanceof Map||v instanceof Collection)
                   dataObject.put(k,valueOfMap(v));
               else dataObject.put(k,v);
            });
            return dataObject;
        }else if(object instanceof Map){
            DataObject dataObject = new DataObject();
            ((Map<String,Object>)object).forEach((k,v)->{
                if(v instanceof DataObject||v instanceof Map||v instanceof Collection)
                    dataObject.put(k,valueOfMap(v));
                else dataObject.put(k,v);
            });
            return dataObject;
        }else if(object instanceof Collection){
            Collection<Object> collection = (Collection<Object>)object;
            ArrayList<Object> objects = new ArrayList<>();
            collection.forEach(o->{
                if(o instanceof DataObject||o instanceof Map||o instanceof Collection)
                    objects.add(valueOfMap(o));
                else objects.add(o);
            });
            return objects;
        }else return object;
    }

    /**
     * 清空所有存储数据 */
    public void clear() {
        map.clear();
    }

    /**
     * 生成包含版本信息和数据内容的字符串
     * @return 格式如："ReceiveMap [版本号=1.0.250118, map={...}]"
     */
    @Override
    public String toString() {
        return toStringHead()+" " + VERSION()+ " " + toStringBody();
    }
    protected String toStringHead(){
        return "ReceiveMap";
    }
    protected String toStringBody() {
        return map.toString();
    }
}